/*
 *  Copyright (C) 2010 Glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.nbpam;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
import javax.persistence.Entity;
import org.balisunrise.application.*;
import org.balisunrise.common.defaults.DefaultLogger;
import org.balisunrise.common.defaults.DefaultMenusManager;
import org.balisunrise.dao.hibernate.HDAO;
import org.balisunrise.dao.hibernate.HibernateUtil;
import org.balisunrise.dao.PropertiesReader;
import org.balisunrise.samples.*;
import org.balisunrise.swing.builders.*;
import org.balisunrise.swing.common.IconManager;
import org.balisunrise.swing.components.managers.*;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

/**
 *
 * @author Glauco
 */
public final class NBApplicationLoader {

    private static final String PROPERTIES_FILE_NAME = "balisunrise";
    private static final String PROPERTIES_EXT = "properties";

    public static final File PROPERTIES_FILE =
            new File("./balisunrise.properties");

    /**
     * Atribui os dados para rodar o Application.
     * Só não é atribuído a representação visual.
     */
    public static void startApplication(){

        ProgressHandle ph =
                ProgressHandleFactory.createHandle("Iniciando Módulos");

        ph.start(100);
        ph.progress("Lendo Configurações", 5);

        // pega aplicativo
        Application app = Application.get();

        // primeira coisa, adicionar o logger
        app.setLogger(new DefaultLogger());

        // segunda coisa, adicionar o IconManager
        app.setIconManager(new IconManager());

        // terceiro o leitor de propriedades do aplicativo
        app.setPropertiesReader(new PropertiesReader());

        // adiciona DAO padrão ao DAOManager
        app.getDaoManager().putDAO("DAO", HDAO.class);

        // por fim as outras atribuições
        app.setWindowsManager(new org.balisunrise.nbpam.windows.WindowsManager());
        app.setBindingBuilder(new org.balisunrise.bindings.swing.BindingBuilder());
        app.setMenusManager(new DefaultMenusManager());
        
        ph.progress("Criando ComponentManager", 20);

        // cria componente builder e carrega com os Components Managers
        ComponentManagers cms = app.getComponentManagers();
        cms.addComponentManager(new BigDecimalComponentManager());
        cms.addComponentManager(new BigIntegerComponentManager());
        cms.addComponentManager(new BooleanComponentManager());
        cms.addComponentManager(new ByteComponentManager());
        cms.addComponentManager(new CharComponentManager());
        cms.addComponentManager(new DateComponentManager());
        cms.addComponentManager(new IntegerComponentManager());
        cms.addComponentManager(new DoubleComponentManager());
        cms.addComponentManager(new FloatComponentManager());
        cms.addComponentManager(new ShortComponentManager());
        cms.addComponentManager(new LongComponentManager());
        cms.addComponentManager(new ShortComponentManager());
        cms.addComponentManager(new StringComponentManager());

        ph.progress("Criando Builders", 25);

        // Adiciona Builders ao aplicativo
        VisualEntityManager vem = app.getVisualEntityManager();
        vem.setActionBuilder(new ActionBuilder());
        vem.setBaliGridBuilder(new GridBuilder());
        vem.setEditorBuilder(new EditorBuilder());
        vem.setEntityActionBuilder(new EntityActionBuilder());
        vem.setEntityFilterBuilder(new EntityFilterBuilder());
        vem.setEntityGridBuilder(new EntityGridBuilder());
        vem.setEntityPanelBuilder(new EntityPanelBuilder());
        vem.setFilterFieldBuilder(new FilterFieldBuilder());
        vem.setMessengerBuilder(new MessengerBuilder());
        vem.setPanelFieldBuilder(new PanelFieldBuilder());
        vem.setSearchBuilder(new SearchBuilder());
        vem.setTransactionActionBuilder(new TransactionActionBuilder());
        vem.setTransactionBuilder(new TransactionBuilder());
        vem.setEntitySelectionBuilder(new EntitySelectionBuilder());

        ph.progress("Carregando Módulos", 30);

        // Carregador de Jar
        URL urls[] = {};
        JarLoader jarLoader = new JarLoader();
        
        // Propriedades do systema
        Properties p = System.getProperties();

        // carrega arquivo com as propriedades
        FileObject baseFolder = FileUtil.getConfigRoot();
        FileObject propFile = baseFolder.getFileObject(
                PROPERTIES_FILE_NAME, PROPERTIES_EXT);
        if (propFile != null){
            Properties baliProp = new Properties();
            try{
                baliProp.load(propFile.getInputStream());
            }catch(IOException ioex){
                System.err.println(ioex.getMessage());
            }
        }

        // reatribui as propriedades do sistema
        System.setProperties(p);

        ph.progress("Carregando Módulos", 50);

        // informaçõe do jars carredados
        JarInfo[] jis = null;

        // carrega os jars
        try{
            jis = jarLoader.loadSystemJars();
        }catch(IOException ioex){
            System.err.println(ioex.getMessage());
        }

        ph.progress("Criando Managers", 60);

        if (jis == null || jis.length == 0){

            ph.progress("Adicionando Módulo de Exemplos", 70);
            //adiciona classes
            HibernateUtil.addAnnotatedClass(new Class[]{
                    Cidade.class,
                    Endereco.class,
                    EnderecoAdicional.class,
                    Estado.class,
                    Pais.class,
                    Pessoa.class,
                    Cliente.class,
                    CEP.class});
            app.putModule(new SampleModule());
            app.getMenusManager().addMenuClass(SampleMenu.class);
            app.getActionMapManager().putActionMap(ActionSample.class);
            app.getActionMapManager().putActionMap(ClienteActions.class);
        }else{
            // loader
            ApplicationLoader loader = null;

            ph.progress("Processando Módulos", 70);

            // para cada JarInfo
            for (JarInfo info : jis) {

                // carrega o primeiro loader
                if (loader == null && info.getApplicationLoader() != null)
                    try{
                        loader = (ApplicationLoader)
                                info.getApplicationLoader().newInstance();
                    }catch(Exception ex){
                        // log
                    }

                // processa entidades
                info.processEntities(Entity.class);
                HibernateUtil.addAnnotatedClass(
                        info.getEntityClasses().toArray(new Class[0]));

                // adiciona as classes de menus
                for (Class menu : info.getMenus()) {
                    app.getMenusManager().addMenuClass(menu);
                }

                // adiciona modulos ao sistema
                for (Class m : info.getModulesClasses()) {
                    try{
                        app.putModule((Module) m.newInstance());
                    }catch(Exception ex){
                        // log
                    }
                }

                ActionMapManager emm = app.getActionMapManager();
                // adiciona os mapas de eventos
                for (Class em : info.getEventMapClasses()) {
                    emm.putActionMap(em);
                }

            }

            if (loader != null)
                loader.loadApplication(app);
        }

        ph.progress(95);

        // adiciona os menis aos módulos
        for (Module m : app.getModules()) {
            app.getMenusManager().setModuleMenuActions(m);
        }

        ph.finish();
    }

}
